#include "../utils/store.h"
#include "./device/compat.h"

using namespace driver;

struct Info {
    uint32_t OtaPkgSize;
    uint32_t AppAddr;
    uint32_t OtaAddr;

    void OtaInit(uint32_t pkgsize) {
        OtaPkgSize = pkgsize;
        AppAddr = flash::AppAddr;
        OtaAddr = flash::OtaAddr;
    }

    bool Verify() const {
        return  (OtaPkgSize > 0) &&
                (OtaPkgSize < flash::AppSize) &&
                (AppAddr == flash::AppAddr) &&
                (OtaAddr == flash::OtaAddr);
    }
	
	void reset() {
		OtaPkgSize = 0;
		AppAddr = 0;
		OtaAddr = 0;
	}
};

utils::Store<Info, flash::OtaInfoAddr> info;

void runApp() {

	auto sp = *reinterpret_cast<const volatile uint32_t *>(flash::AppAddr);
	auto pc = *reinterpret_cast<const volatile uint32_t *>(flash::AppAddr + 4);
	auto app = reinterpret_cast<void (*)(void)>(pc);
	__set_MSP(sp);
	app();	    
}

void execOta() {
    flash::Erase(flash::AppAddr, info->OtaPkgSize);
    const void *data = reinterpret_cast<const void *>(flash::OtaAddr);
    flash::Write(flash::AppAddr, data, info->OtaPkgSize);
    info.Erase();
}

int main() {
    auto err = info.Load();
    if (err.IsOk() && info->Verify()) {
        execOta();
    }
    runApp();
}